#include "HRCompany.h"
#include "CompareEmployeeBySalary.h"
#include "CompareEmployeesByID.h"
#include "Exceptions.h"
#include "Common.h"
using namespace DataStructuresWet1;
using namespace std;

HRCompany::HRCompany (int numOfCompanies) : numOfCompanies(numOfCompanies), cmpEmpByID(), Employees(cmpEmpByID)
{
	Companies = new Company[numOfCompanies];
}

HRCompany::~HRCompany ()
{
	delete Companies;
}

StatusType HRCompany::Hire(int id, int company, Rational salary)
{
	if (!Company::IsLegalCompanyID(company) ||
		!Employee::IsLegalEmployeeID(id) ||
		!Employee::IsLegalEmployeeSalary(salary))
	{
		return INVALID_INPUT;
	}

	Employee temp = Employee (id, 0, Rational(0));

	Employee* emp = Employees.Find(temp);
	//if (&(*it)!=NULL)
	//{
	//	return FAILURE;
	//}
	try
	{
		emp = new Employee(id, Companies[company].GetID(), salary);
	}
	catch (bad_alloc)
	{
		return ALLOCATION_ERROR;
	}
	catch (FailureException)
	{
		return FAILURE;
	}

	try
	{
		Employees.Insert(emp);
	}
	catch (bad_alloc)
	{
		delete emp;
		return ALLOCATION_ERROR;
	}

	try
	{
		Companies[company].Hire(*emp);
	}
	catch (bad_alloc)
	{
		Employees.Remove(*emp);
		delete emp;
		return ALLOCATION_ERROR;
	}

	return SUCCESS;
}
StatusType HRCompany::Fire(int id, int company)
{
	if (!Company::IsLegalCompanyID(company) ||
		!Employee::IsLegalEmployeeID(id))
	{
		return INVALID_INPUT;
	}

	Employee temp = Employee(id, 0, Rational(0));
	Employee *emp = Employees.Find(temp);
	//if (&(*it)!=NULL)
	//{
	//	return FAILURE;
	//}
	try
	{
		Companies[company].Fire(id);
		Employees.Remove(*emp);
	}
	catch (FailureException)
	{
		return FAILURE;
	}
	delete emp;
	return SUCCESS;
}

StatusType HRCompany::GetEmployer(int id, int* company) const
{
	if (company==NULL ||
		!Employee::IsLegalEmployeeID(id))
	{
		return INVALID_INPUT;
	}
	try
	{
		Employee temp = Employee(id, 0, Rational(0));
		Employee *emp = Employees.Find(temp);
		int employerID = emp->GetEmployerID();
		if (Companies[employerID].IsActive())
		{
			*company = employerID;
		}
		else
		{
			*company = Companies[Companies[employerID].GetOwnerID()].GetID();
		}
	}
	catch (FailureException)
	{
		return FAILURE;
	}
	return SUCCESS;
}

StatusType HRCompany::GetSalary(int id, Rational *salary) const
{
	if (salary==NULL||
		!Employee::IsLegalEmployeeID(id))
	{
		return INVALID_INPUT;
	}

	try
	{
		Employee temp = Employee(id, 0, Rational(0));
		Employee *emp = Employees.Find(temp);
		*salary = emp->GetBaseSalary();
		int employerID = emp->GetEmployerID();
		if (Companies[employerID].IsActive())
		{
			*salary *= Companies[employerID].GetSalaryUpdate();
		}
		else
		{
			*salary *= Companies[Companies[employerID].GetOwnerID()].GetSalaryUpdate();
		}
	}
	catch (FailureException)
	{
		return FAILURE;
	}
	return SUCCESS;
}

StatusType HRCompany::MedianSalary(int id, int company, Rational *salary) const
{
	if (salary==NULL ||
		!Company::IsLegalCompanyID(company) ||
		!Employee::IsLegalEmployeeID(id))
	{
		return INVALID_INPUT;
	}
	try
	{
		*salary = Companies[company].GetMedianSalary();
	}
	catch (FailureException)
	{
		return FAILURE;
	}
	return SUCCESS;
}

StatusType HRCompany::HighestSalary(int id, int company, Rational *salary) const
{
	if (salary==NULL ||
		!Company::IsLegalCompanyID(company) ||
		!Employee::IsLegalEmployeeID(id))
	{
		return INVALID_INPUT;
	}
	try
	{
		*salary = Companies[company].GetHisghestSalary();
	}
	catch (FailureException)
	{
		return FAILURE;
	}
	return SUCCESS;
}

StatusType HRCompany::UpdateSalaries(int company, Rational update)
{
	if (!Company::IsLegalCompanyID(company) ||
		!Company::IsLegalSalaryUpdate(update))
	{
		return INVALID_INPUT;
	}
	try
	{
		Companies[company].UpdateSalary(update);
	}
	catch (FailureException)
	{
		return FAILURE;
	}
	return SUCCESS;
}

StatusType HRCompany::Merger(int buyingCompany, int sellingCompany)
{
	//TODO: Implement
	return SUCCESS;
}